#define _GNU_SOURCE
#include <sched.h>

#include "cms_log.h"
#include "cms_common.h"
#include "task_utils.h"
#include "task_module.h"
#include "cms_mdm.h"
#include "task_queue.h"

cmsTaskContext_t cmsTaskCtx;
cmsXmlCb_t *xmlShmCb = NULL, *taskXmlShmCb = NULL;
cms_common_content_t *cmsCommonContent = NULL;
cmsEventLock_t *cmsEventLock;
cmsQueue_t *notifyQHandle = NULL;
cmsQueue_t *statsQHandle = NULL;
static int gLoadFinFlag = 0;	/*record config load finish flag*/
void *cmsTmrHandle = NULL;
uint64_t preUpBytes = 0;
uint64_t preDownBytes = 0;
void *cmsTmrHandleLanHostSpeed = NULL;

//extern int msgRecv_exit_when_break;

int cms_Common_Init(cms_common_content_t **content, cms_common_initInfo_t *initInfo)
{
	int ret = 0;

	if(content == NULL)
	{
		CMS_LOG(LL_ERROR, "cms common content is NULL\n");
		return -1;
	}

	*content = malloc(sizeof(cms_common_content_t));
	if(*content == NULL)
	{
		CMS_LOG(LL_ERROR, "malloc memory for cms common content fail\n");
		return -1;
	}

	memset(*content, 0, sizeof(cms_common_content_t));

	memcpy(&(*content)->initInfo, initInfo, sizeof(cms_common_initInfo_t));


	return ret;	
}


/*
	Describtion:
		recv event/objectChg notify from cms_core.
	Parameter:
		signum - 
	Return:
	
*/
#if 0
void cmsTask_signalHandler(int signum, siginfo_t *siginfo, void *ptr){
	cmsEvent_t *eventRecv = NULL;
	cms_eventListEntry_t *pCurEventList = NULL;
	cmsEventHandlerListEntry_t *pCurEventHandler = NULL;
	data_t objData;
	uint32_t eventLen = 0;
	
	if((eventRecv = cms_eventRecv(siginfo->si_value.sival_int)) != NULL){
	
		if(eventRecv->notifyType == CMS_MSG_ACT_EVENT_NOTIFY){//event notify
	#if 0
			if(eventRecv->notify.eventNotify.typeSizeOfEContent == PARAMETER_TYPE_STRING){
				uint32_t len = strlen(eventRecv->notify.eventNotify.eventContent)+1;
				CMS_LOG(LL_DEBUG, "[%s-%d]-event notify, eventId %d, type 0x%x, %s,%d", __FUNCTION__, __LINE__, eventRecv->notify.eventNotify.eventId,
					eventRecv->notify.eventNotify.typeSizeOfEContent,(eventRecv->notify.eventNotify.eventContent), len);
			}else if(eventRecv->notify.eventNotify.typeSizeOfEContent == PARAMETER_TYPE_UINT8){
				CMS_LOG(LL_DEBUG, "[%s-%d]-event notify, eventId %d, type %d, %d", __FUNCTION__, __LINE__, eventRecv->notify.eventNotify.eventId,
					eventRecv->notify.eventNotify.typeSizeOfEContent,*(uint8_t *)(eventRecv->notify.eventNotify.eventContent));
			}
			else if(eventRecv->notify.eventNotify.typeSizeOfEContent == PARAMETER_TYPE_UINT16){
				CMS_LOG(LL_DEBUG, "[%s-%d]-event notify, eventId %d, type %d, %d", __FUNCTION__, __LINE__, eventRecv->notify.eventNotify.eventId,
					eventRecv->notify.eventNotify.typeSizeOfEContent,
					*(uint16_t *)(eventRecv->notify.eventNotify.eventContent));
			}
			else if(eventRecv->notify.eventNotify.typeSizeOfEContent == PARAMETER_TYPE_UINT32){
				CMS_LOG(LL_DEBUG, "[%s-%d]-event notify, eventId %d, type %d, %d", __FUNCTION__, __LINE__, eventRecv->notify.eventNotify.eventId,
					eventRecv->notify.eventNotify.typeSizeOfEContent,*(uint32_t *)(eventRecv->notify.eventNotify.eventContent));
			}
			else if(eventRecv->notify.eventNotify.typeSizeOfEContent == PARAMETER_TYPE_UINT64){
				CMS_LOG(LL_DEBUG, "[%s-%d]-event notify, eventId %d, type %d, %lu", __FUNCTION__, __LINE__, eventRecv->notify.eventNotify.eventId,
					eventRecv->notify.eventNotify.typeSizeOfEContent,*(uint64_t *)(eventRecv->notify.eventNotify.eventContent));
			}
	#endif
			
			/*check event list. if realtime priority, handle this event func, if not, put in list*/
			pCurEventList = cmsTask_getEventById(eventRecv->notify.eventNotify.eventId);
			if(pCurEventList){
				pCurEventHandler = pCurEventList->eventHandlerList;
				while(pCurEventHandler != NULL){
					if(pCurEventHandler->handler){
						if(pCurEventHandler->priority & CMS_NOTIFY_PRORITY_REALTIME){
							pCurEventHandler->handler(eventRecv->notify.eventNotify.eventId,
								eventRecv->notify.eventNotify.typeSizeOfEContent, eventRecv->notify.eventNotify.eventContent);
						}
							
					}
					pCurEventHandler = pCurEventHandler->next;
				}
			}else{
				CMS_LOG(LL_ERROR, "[%s-%d]-can not find eventId in event list, eventId %d", __FUNCTION__, __LINE__, eventRecv->notify.eventNotify.eventId);
			}

			/*add event to queue, to notify other priority module task.*/
			objData.id = eventRecv->notify.eventNotify.eventId;
			objData.type = eventRecv->notify.eventNotify.typeSizeOfEContent;

			if(eventRecv->notify.eventNotify.typeSizeOfEContent == PARAMETER_TYPE_STRING)
				eventLen = strlen(eventRecv->notify.eventNotify.eventContent)+1;
			else 
				eventLen = eventRecv->notify.eventNotify.typeSizeOfEContent & ~((uint32_t)PARAMETER_TYPE_CLASS_BITS);
		
			objData.value = (uint8_t *)calloc(eventLen, sizeof(uint8_t));
			if(objData.value == NULL){
				CMS_LOG(LL_ERROR, "calloc event data mem fail.\n");
			}else{
				memcpy(objData.value, eventRecv->notify.eventNotify.eventContent, eventLen);
				en_queue(notifyQHandle, objData);
			}
			
		}
		else if(eventRecv->notifyType == CMS_MSG_ACT_OBJCHG_NOTIFY){//object change notify
			CMS_LOG(LL_DEBUG, "[%s-%d]-objchg notify, objDataShmId %d", __FUNCTION__, __LINE__, eventRecv->notify.objNotify.objChgShmId);
			objData.id = eventRecv->notify.objNotify.objChgShmId;
			en_queue(objQHandle, objData);
		}
		else{
			CMS_LOG(LL_ERROR, "[%s-%d]-recv error event %d", __FUNCTION__, __LINE__, eventRecv->notifyType);
		}
	
		CMS_LOG(LL_DEBUG, "recv event from cms_core********************.\n");
		safe_free(eventRecv);

	}

	
}

#else
void cmsTask_signalHandler(int signum, siginfo_t *siginfo, void *ptr){
	CMS_LOG(LL_DEBUG,"recv signal==============\n");
	//msgRecv_exit_when_break = 1;
}
#endif

static void *cmsTask_notifyRecv(void *arg){
	cmsEvent_t *eventRecv = NULL;
	cms_eventListEntry_t *pCurEventList = NULL;
	cmsEventHandlerListEntry_t *pCurEventHandler = NULL;
	data_t objData;
	uint32_t eventLen = 0;
	int ret = -1;

	/*check config load is finish or not; event & object change recv must after config load finish*/
	while(1){
		if(gLoadFinFlag == 0){
			usleep(500*1000);
			continue;
		}else{
			break;
		}
	}

	memset((void *)&objData, 0, sizeof(data_t));

	while(1){
		if((cms_eventRecv(&eventRecv)) != CMS_NOK){
			if(eventRecv->notifyType == CMS_MSG_ACT_EVENT_NOTIFY){//event notify
				/*check event list. if realtime priority, handle this event func, if not, put in list*/
			//	CMS_SYSLOG(LOG_DEBUG, "cms_task recv event notify, event id %u.", eventRecv->notify.eventNotify.eventId);
				pCurEventList = cmsTask_getEventById(eventRecv->notify.eventNotify.eventId);
				if(pCurEventList){
					pCurEventHandler = pCurEventList->eventHandlerList;
					while(pCurEventHandler != NULL){
						if(pCurEventHandler->handler){
							if(pCurEventHandler->priority == CMS_NOTIFY_PRORITY_INTURRUPT_HANDLER){
								pthread_mutex_lock(&cmsEventLock->mutex);
			//					CMS_SYSLOG(LOG_DEBUG, "cms_task recv event notify, event id %u func handle start immediately.", eventRecv->notify.eventNotify.eventId);
								pCurEventHandler->handler(eventRecv->notify.eventNotify.eventId,
									eventRecv->notify.eventNotify.typeSizeOfEContent, eventRecv->notify.eventNotify.eventContent);
				//				CMS_SYSLOG(LOG_DEBUG, "cms_task recv event notify, event id %u func handle end immediately.", eventRecv->notify.eventNotify.eventId);
								pthread_mutex_unlock(&cmsEventLock->mutex);
							}
								
						}
						pCurEventHandler = pCurEventHandler->next;
					}
				}else{
					CMS_LOG(LL_ERROR, "Not find a module who has subscribe the cms_eventId:%d", eventRecv->notify.eventNotify.eventId);
				}

				/*add event to queue, to notify other priority module task.*/

				objData.id = eventRecv->notify.eventNotify.eventId;
				objData.type = eventRecv->notify.eventNotify.typeSizeOfEContent;
				objData.nType = EVENT_NOTIFY;
				
				if(eventRecv->notify.eventNotify.typeSizeOfEContent == PARAMETER_TYPE_STRING)
					eventLen = strlen(eventRecv->notify.eventNotify.eventContent)+1;
				else 
					eventLen = eventRecv->notify.eventNotify.typeSizeOfEContent & ~((uint32_t)PARAMETER_TYPE_CLASS_BITS);

				objData.value = (uint8_t *)calloc(eventLen, sizeof(uint8_t));
				if(objData.value == NULL){
					CMS_LOG(LL_ERROR, "calloc event data mem fail.\n");
				}else{
					memcpy(objData.value, eventRecv->notify.eventNotify.eventContent, eventLen);
					ret = en_queue(notifyQHandle, objData);
					if(ret == -1){
						CMS_LOG(LL_ERROR, "cms task enqueue fail, please enlarge the size of queue!!!\n");
					}
				}
			}
			else if(eventRecv->notifyType == CMS_MSG_ACT_OBJCHG_NOTIFY){//object change notify
			//	CMS_SYSLOG(LOG_DEBUG, "cms_task recv obj chg notify.");
				CMS_LOG(LL_DEBUG, "objchg notify, objDataShmId %d", eventRecv->notify.objNotify.objChgShmId);
				objData.id = eventRecv->notify.objNotify.objChgShmId;
				objData.nType = OBJECT_NOTIFY;
				
				ret = en_queue(notifyQHandle, objData);
				if(ret == -1){
					CMS_LOG(LL_ERROR, "cms task enqueue fail, please enlarge the size of queue!!!\n");
				}
			}
			else{
				CMS_LOG(LL_ERROR, "recv error event %ld", eventRecv->notifyType);
			}

			CMS_LOG(LL_DEBUG, "recv event from cms_core********************.\n");
		}
	}

	free(eventRecv);
	eventRecv = NULL;

	return NULL;
}

static int cmsTask_init(void){
	cms_eventListEntry_t *pCurEvent = NULL;
	uint32_t *eventIdArray = NULL, *tmpEventId = NULL;
	uint32_t eventCount = 0;
	int ret = -1;
	cms_common_initInfo_t initInfo;
	pthread_t ConfigHandleSecThread;
	pthread_attr_t threadAttr;
	int cpuNo = -1;
	
	//cmsTask_registerSignal();
	memset(&cmsTaskCtx, 0, sizeof(cmsTaskContext_t));
	cmsTaskCtx.dbusFlag = FALSE;
	
	/*register cmsTask*/
	cmsTaskCtx.moduleId = cms_registerModule(CMS_TASK);
	if(cmsTaskCtx.moduleId < 0){
		CMS_LOG(LL_ERROR, "register module fail.\n");
		return -1;
	}

	xmlShmCb = XMLSHMINIT();
	if (xmlShmCb == NULL){
		cms_unregisterModule(CMS_TASK);
		CMS_LOG(LL_ERROR, "xmlShm init error.\n");
		return -1;
	}

	taskXmlShmCb = xmlShmCb;

	cmsTask_preConfig();

	/*create queue for event & obj change*/
	notifyQHandle = queue_create(MAX_NUM);

	/*create queue for stats request*/
	statsQHandle = queue_create(MAX_NUM);
	
	/*reg config and event init func*/
	cmsTask_moduleInit();
	//cmsTask_dumpRegInfo();

	memset(&initInfo, 0, sizeof(cms_common_initInfo_t));
	if(cms_Common_Init(&cmsCommonContent, &initInfo) != 0)
	{
		CMS_LOG(LL_ERROR, "cms Common init fail.\n");
		return -1;
	}


	/*compute event num*/
	pCurEvent = cmsTaskCtx.eventList;
	while(pCurEvent){
		CMS_LOG(LL_DEBUG, "event num is %d\n", pCurEvent->eventId);
		
		eventCount++;
		pCurEvent = pCurEvent->next;
	}
	CMS_LOG(LL_DEBUG, "reg event count %d\n", eventCount);
	
	/*subscribe to cms_core*/
	if(eventCount > 0){
		eventIdArray = (uint32_t *)calloc(1, sizeof(uint32_t)*eventCount); 
		tmpEventId = eventIdArray;
		
		pCurEvent = cmsTaskCtx.eventList;
		while(pCurEvent){
			*tmpEventId = pCurEvent->eventId;
			tmpEventId++;
			pCurEvent = pCurEvent->next;
		}

	
		ret = cms_subcribeEvent(eventCount, eventIdArray, cmsTask_notifyRecv, NULL);
		if(ret == -1){
			CMS_LOG(LL_ERROR, "subscribe event fail.\n");
			safe_free(eventIdArray);
			return -1;
		}
		safe_free(eventIdArray);
	}

	/*even lock init*/
	cmsTask_initEventLock();

	/*clean up config which dynamic config when reboot*/
	cmsTask_cleanUp();

#ifdef GC_XML_UPDATE_SUPPORT
	cmsTask_updateXml();
#endif

	/*configure object, load func*/
	cmsTask_configLoadHandle();

	cpuNo = sched_getcpu();
	/*put configload func which cost many time but has no relationship with wan boot here*/
	pthread_attr_init(&threadAttr);
	pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED);
	ret = pthread_create(&ConfigHandleSecThread, &threadAttr, cmsTask_configLoadSecHandle, (void *)&cpuNo);
	if(ret != 0){
		CMS_LOG(LL_ERROR, "create configLoadSec thread fail.\n");
	}
	pthread_attr_destroy(&threadAttr);

	gLoadFinFlag = 1;

	return 0;
}
#if 0
static int cms_msgHandle(cmsMsgCb_t  *pMsg){
	cmsMsg_action_t *pAction = NULL;
	cmsStatsBuf_t statsBuf;
	uint32_t actionNum = 0;
	int ret = CMS_OK, status = CMS_STATUS_FAIL;
	cmsBoolean isStatsReq = FALSE; /*stats request need reply*/
	
	actionNum = pMsg->header.actionNum;
	if(actionNum == 0){
		CMS_LOG(LL_ERROR, "action num is 0, error!!.\n");
		return -1;
	}

	while(actionNum > 0){
		pAction = cms_parseMsgAction(pMsg);
		if(pAction == NULL){
			CMS_LOG(LL_ERROR, "action of msg is NULL, error!!.\n");
			return -1;
		}
		
		CMS_LOG(LL_DEBUG,"type is %d\n", pAction->action->type);
		switch(pAction->action->type){
			case CMS_MSG_ACT_UPDATE:
				CMS_LOG(LL_ERROR,"update, id %d, ia %"PRIx64"\n", pAction->object->objOffset.id, pAction->object->objOffset.IA);
				ret = cmsTask_objectStats(pAction->object->objOffset.id, pAction->object->objOffset.IA);
				status = ((ret == CMS_OK) ? CMS_STATUS_SUCCESS : CMS_STATUS_FAIL);
				isStatsReq = TRUE;
				CMS_LOG(LL_ERROR,"update id %d, ia %"PRIx64" finish\n", pAction->object->objOffset.id, pAction->object->objOffset.IA);
				break;
			case CMS_MSG_ACT_CMD_SERVICE:
				ret = cmsTask_handleCmdService(pAction->cmdService);
				status = ((ret == CMS_OK) ? CMS_STATUS_SUCCESS : CMS_STATUS_FAIL);
				break;
			case CMS_MSG_ACT_SET_LOG:
				ret = cmsSetLogLevel(pAction, CMS_TASK);
				status = ((ret == CMS_OK) ? CMS_STATUS_SUCCESS : CMS_STATUS_FAIL);
				break;
			default:
				break;
		}
		actionNum--;
	}
	CMS_LOG(LL_ERROR, "stats thread dequeue success, stats finish\n");
	if(isStatsReq == TRUE){
		statsBuf.mType = pMsg->header.msgType;
		statsBuf.statsRet = status;
		statsBuf.timeStamp.tv_sec = pMsg->header.timeStamp.tv_sec;
		statsBuf.timeStamp.tv_nsec = pMsg->header.timeStamp.tv_nsec;

		//CMS_LOG(LL_ERROR, "stats result %d, time %d %ld\n", statsBuf.statsRet, statsBuf.timeStamp.tv_sec, statsBuf.timeStamp.tv_nsec);
		ret = msgsnd(pMsg->header.srcModuleId, &statsBuf, sizeof(cmsStatsBuf_t)-sizeof(long), IPC_NOWAIT);
	}

	return ret;
}
#else

static int cms_msgHandle(data_t statsData){
	cmsStatsBuf_t statsBuf;
	int ret = CMS_OK, status = CMS_STATUS_FAIL;
	cmsBoolean isStatsReq = FALSE; /*stats request need reply*/
	
	//CMS_SYSLOG(LOG_DEBUG, "cms_task start obj stats action(oid %d, oia %lx).",statsData.statInfo.objID, statsData.statInfo.objIA);
	CMS_LOG(LL_DEBUG,"update, id %d, ia %"PRIx64"\n", statsData.statInfo.objID, statsData.statInfo.objIA);
	ret = cmsTask_objectStats(statsData.statInfo.objID, statsData.statInfo.objIA);
	status = ((ret == CMS_OK) ? CMS_STATUS_SUCCESS : CMS_STATUS_FAIL);
	isStatsReq = TRUE;
	CMS_LOG(LL_DEBUG,"update id %d, ia %"PRIx64" finish\n", statsData.statInfo.objID, statsData.statInfo.objIA);
	//CMS_SYSLOG(LOG_DEBUG, "cms_task end obj stats action(oid %d, oia %lx), ret = %d.",statsData.statInfo.objID, statsData.statInfo.objIA, status);
	

	if(isStatsReq == TRUE){
		statsBuf.mType = statsData.statInfo.msgType;
		statsBuf.statsRet = status;
		statsBuf.timeStamp.tv_sec = statsData.statInfo.timeStamp.tv_sec;
		statsBuf.timeStamp.tv_nsec = statsData.statInfo.timeStamp.tv_nsec;
		ret = msgsnd(statsData.statInfo.srcModId, &statsBuf, sizeof(cmsStatsBuf_t)-sizeof(long), IPC_NOWAIT);
	}

	return ret;
}
#endif

int objDataMsgHandler(cmsMsgCb_t *objDataMsg, int shmId){
	cmsMsg_action_t *pAction = NULL;
	cmsBoolean isMutliObj = FALSE;
	uint32_t objChgNum = 0;

	CMS_LOG(LL_DEBUG,"objMsgHandle shm id %d==============\n", shmId);
	/*init obj msg, the msg stored obj change info*/
	objDataMsg->shmId = shmId;
	objDataMsg->shmAddr = (void *)shmat(objDataMsg->shmId, 0, 0);
	objDataMsg->msgOffset = MSG_OFFSET;
	objDataMsg->msgType |= CMS_MSG_RECV;
	objDataMsg->length = 0;
	objDataMsg->pCurData = (uint8_t *)(objDataMsg->shmAddr) + objDataMsg->msgOffset + sizeof(cmsMsg_header_t);
	objDataMsg->pCurMsgCb = objDataMsg;
	objDataMsg->next = NULL;
	memcpy(&(objDataMsg->header), (uint8_t *)(objDataMsg->shmAddr) + objDataMsg->msgOffset, sizeof(cmsMsg_header_t));
	
	objChgNum = objDataMsg->header.actionNum;

	CMS_LOG(LL_DEBUG, "obj changed num: %d, isMutiObj %d.\n", objChgNum, objDataMsg->header.isMutliObj);
	/*insert objchg data into objchglist*/
	while(objChgNum > 0){
		pAction = cms_parseMsgAction(objDataMsg);
		if(pAction == NULL){
			CMS_LOG(LL_ERROR, "action parse fail.\n");
			cms_msgFree(objDataMsg);
			return -1;
		}
		
		switch(pAction->action->type){
			case CMS_MSG_ACT_SETMODULEID:
				if(pAction->eventContent->typeSizeOfValue == cms_getModuleIdByName(CMS_DBUS))
					cmsTaskCtx.dbusFlag = TRUE;

				break;
			case CMS_MSG_ACT_OBJCHG_DATA:
				if(pAction->objectData->objectId >= 0)
					cmsTask_collectObjChg(pAction->objectData);
				else{
					CMS_LOG(LL_ERROR, "obj change oid is wrong, %d.\n", pAction->objectData->objectId);
				}
				break;
			default:
				CMS_LOG(LL_ERROR, "obj change error action type.\n");
				break;
		}
		objChgNum--;
	}

	isMutliObj = objDataMsg->header.isMutliObj;
	cms_msgFree(objDataMsg);
	
	/*handle objchg*/
	if(cmsTaskCtx.objChgList != NULL)
		cmsTask_handleObjChg(cmsTaskCtx.objChgList, isMutliObj);

	cmsTaskCtx.dbusFlag = FALSE;
	
	return 0;
}

/*static void *notifyRecvHandle(void *arg)
{
	
	while(1){
		usleep(10*1000);
	
		cmsTask_notifyRecv();

	}
	return (void *)NULL;
}*/

static void *notifyHandle(void *arg)
{
	cmsMsgCb_t *objDataMsg = NULL;
	data_t objData;
	int ret = 0;
	
	while(1){
		ret = de_queue(notifyQHandle, &objData);
		if(ret != -1){
			pthread_mutex_lock(&cmsEventLock->mutex);
			if(objData.nType == EVENT_NOTIFY){
				cmsTask_handleEvent(objData.id, objData.type, objData.value);
				if(objData.value != NULL)
					free(objData.value);
			}else if(objData.nType == OBJECT_NOTIFY){
				objDataMsg = (cmsMsgCb_t *)calloc(1, sizeof(cmsMsgCb_t));
				if(objDataMsg)
					objDataMsgHandler(objDataMsg, objData.id);
			}else{
				CMS_LOG(LL_ERROR, "error notify type.\n");
			}
			pthread_mutex_unlock(&cmsEventLock->mutex);
		}else{
			usleep(10*1000);
		}
	}
	return (void *)NULL;
}

static void *statsHandle(void *arg)
{
	data_t statsData;
	int ret = 0;
	
	while(1){
		memset(&statsData, 0, sizeof(data_t));
		
		ret = de_queue(statsQHandle, &statsData);
		if((ret != -1) && (statsData.nType == STATS_REQUEST)){
			cms_msgHandle(statsData);
		}else{
			usleep(10*1000);
		}
	}
	return (void *)NULL;
}

int main(int argc, char* argv[]){
	cmsMsgCb_t *pRecvMsg = NULL;
	cmsMsg_action_t *pAction= NULL;
	pthread_t notifyHandleThread;
    pthread_t statsHandleThread;
    pthread_t timerHandleThread;
#if 0
    pthread_t LanHostSpeedtimerHandleThread;
#endif
	data_t statsData;
	int ret = -1;
	int timerInitSuccess = 1;
	
    cmsSetLogLevel(NULL, CMS_TASK);

	/*first build DOS_FLOOD & DOS_OTHER chain for every cmstask modules use before cmsTask_init!!*/
	//cms_do_cmd("iptables -N DOS_FLOOD;iptables -F DOS_FLOOD");
	//cms_do_cmd("ip6tables -N DOS_FLOOD;ip6tables -F DOS_FLOOD");
	//cms_do_cmd("iptables -N DOS_OTHER;iptables -F DOS_OTHER");
	//cms_do_cmd("ip6tables -N DOS_OTHER;ip6tables -F DOS_OTHER");

	/*init cmsTask module, 1. register to cmsCore 2. subscribe event to cmsCore 3. load config module*/
	ret = cmsTask_init();
	if(ret < 0){
		CMS_LOG(LL_ERROR, "cms task init fail.\n");
		return -1;
	}
	
	/*init cmsTask timer, 0:cms task timer init success;-1:cms task timer init failed*/
	if(cms_Tmr_init(&cmsTmrHandle)!= 0){
		CMS_LOG(LL_ERROR, "cms task timer init fail.\n");
		timerInitSuccess = -1;
	}

	/*create one thread to handle recv notify*/
	/*ret = pthread_create(&notifyRecvThread, NULL, notifyRecvHandle, NULL); 
	if(ret != 0){
		CMS_LOG(LL_ERROR, "cms task thread1 create fail.\n");
		goto exit3;
	}*/

	/*create one thread to handle objectChange notify*/
	ret = pthread_create(&notifyHandleThread, NULL, notifyHandle, NULL);	
	if(ret != 0){
		CMS_LOG(LL_ERROR, "cms task thread2 create fail.\n");
		goto exit2;
	}

	/*create one thread to handle stats request*/
	ret = pthread_create(&statsHandleThread, NULL, statsHandle, NULL);	
	if(ret != 0){
		CMS_LOG(LL_ERROR, "cms task thread3 create fail.\n");
		goto exit1;
	}
	
	/*create one thread to handle timer work*/
	if(timerInitSuccess > 0){
		ret = pthread_create(&timerHandleThread, NULL, cmsTaskTimerHandle, cmsTmrHandle);	
		if(ret != 0){
			CMS_LOG(LL_ERROR, "cms task thread4 create fail.\n");
			goto exit1;
		}
	}
	
#if 0
	cmsTimerWanSpeedCountCalculateTask();
#endif

#if 0
	timerInitSuccess = 1;
	if(cms_Tmr_init(&cmsTmrHandleLanHostSpeed)!= 0){
		CMS_LOG(LL_ERROR, "cms task timer init fail.\n");
		timerInitSuccess = -1;
	}
	if(timerInitSuccess > 0){
		ret = pthread_create(&LanHostSpeedtimerHandleThread, NULL, cmsTaskTimerHandleLanHostSpeed, cmsTmrHandleLanHostSpeed);	
		if(ret != 0){
			CMS_LOG(LL_ERROR, "cms task thread5 create fail.\n");
			goto exit1;
		}
	}
	cmsTimerLanHostSpeedCountCalculateTask();
#endif
	/*loop recv msg from other module*/
	while(1){
		#if 0
		pRecvMsg = cms_recvMsg(0, CMS_MSG_TYPE);
		if(pRecvMsg != NULL){
			memset((void *)&statsData, 0, sizeof(data_t));
			statsData.nType = STATS_REQUEST;
			statsData.msg = pRecvMsg;
			ret = en_queue(statsQHandle, statsData);
			if(ret == -1){
				CMS_LOG(LL_ERROR, "cms task enqueue fail, please enlarge the size of queue!!!\n");
				cms_msgFree(pRecvMsg);
			}
		}
		#else
		pRecvMsg = cms_recvMsg(0, CMS_MSG_TYPE);
		if(pRecvMsg != NULL){
			if(pRecvMsg->header.actionNum == 0){
				CMS_LOG(LL_ERROR, "action num is 0, error!!!\n");
				cms_msgFree(pRecvMsg);
				continue;
			}
				
			pAction = cms_parseMsgAction(pRecvMsg);
			if(pAction == NULL){
				CMS_LOG(LL_ERROR, "action of msg is NULL, error!!.\n");
				cms_msgFree(pRecvMsg);
				continue;
			}

			if(pAction->action->type == CMS_MSG_ACT_SET_LOG){
				//CMS_SYSLOG(LOG_DEBUG, "cms_task recv log set cmd.");
				cmsSetLogLevel(pAction, CMS_TASK);
				cms_msgFree(pRecvMsg);
				continue;
			}
#ifdef DBUS_OBJECT_NOTIFY
			else if(pAction->action->type == CMS_MSG_ACT_SUBSCRIBEEVENT){
				//CMS_SYSLOG(LOG_DEBUG, "cms_task recv dbus subscribe action.");
				if(pAction->event->eventCount > 0){
					if(resetDbusObj() != CMS_NOK){
						#if 0
						for(i = 0; i < pAction->event->eventCount; i++){
							objIndex = (objCnt/50) + 1;
							object = cmsXmlAddObjByOID(xmlShmCb, InternetGatewayDevice_X_GC_DBUS_i , cmsXmlConstructIAValue(1,"%d",objIndex), 0, NULL);
				
							memset(str, 0, 8);
							sprintf(str, "Obj%d", (i%50)+1);
							//CMS_LOG(LL_ERROR, "set obj param name %s, %d\n", str, pAction->event->eventId[i]);
							cmsXmlSetOneParameterByOID(xmlShmCb,  InternetGatewayDevice_X_GC_DBUS_i , cmsXmlConstructIAValue(1,"%d",objIndex), str, PARAMETER_TYPE_SINT31 , &(pAction->event->eventId[i]))
							objCnt++;
						}
						#endif
						dbusObjSubscribe(pAction->event->eventCount, pAction->event->eventId);
					}
				}
			}else if(pAction->action->type == CMS_MSG_ACT_UNSUBSCRIBEEVENT){
				resetDbusObj();
			}
#endif
			else if(pAction->action->type == CMS_MSG_ACT_UPDATE){
				//CMS_SYSLOG(LOG_DEBUG, "cms_task recv obj stats action(oid %d, oia %lx).", pAction->object->objOffset.id, pAction->object->objOffset.IA);
				memset((void *)&statsData, 0, sizeof(data_t));
				statsData.nType = STATS_REQUEST;
				statsData.statInfo.objID= pAction->object->objOffset.id;
				statsData.statInfo.objIA= pAction->object->objOffset.IA;
				statsData.statInfo.msgType = pRecvMsg->header.msgType;
				statsData.statInfo.srcModId = pRecvMsg->header.srcModuleId;
				statsData.statInfo.timeStamp.tv_sec = pRecvMsg->header.timeStamp.tv_sec;
				statsData.statInfo.timeStamp.tv_nsec = pRecvMsg->header.timeStamp.tv_nsec;
				ret = en_queue(statsQHandle, statsData);
				if(ret == -1){
					CMS_LOG(LL_ERROR, "cms task enqueue fail, please enlarge the size of queue!!!\n");
				}
			}
			
			cms_msgFree(pRecvMsg);
		}
		#endif
	}
	
	
	/*exit while loop, destory pthread, unregister task.*/
	CMS_LOG(LL_ERROR, "cms task exit!!!!\n");
	pthread_join(statsHandleThread, NULL);
exit1:
	pthread_join(notifyHandleThread, NULL);
	pthread_join(timerHandleThread, NULL);
#if 0
	pthread_join(LanHostSpeedtimerHandleThread, NULL);
#endif

exit2:
	/*destory timer event.*/
	if(timerInitSuccess > 0){
		cms_Tmr_cleanup((void **)&cmsTmrHandle);
		cms_Tmr_cleanup((void **)&cmsTmrHandleLanHostSpeed);
	}
	
	/*deinit event lock*/
	cmsTask_deInitEventLock();
	
	/*destory queue for event and object Change.*/
	destory_queue(notifyQHandle);

	/*destory queue for stats.*/
	destory_queue(statsQHandle);

	cms_unregisterModule(CMS_TASK);
	XMLSHMDEINIT(xmlShmCb);
	
	return 0;
}
